﻿<# 
.SYNOPSIS 
    Stops the PeopleSoft Application Server.
.DESCRIPTION 
    Use this command to stop the PeopleSoft Application Server for a specific domain.
    The domain will stop normally by default.
    Use -Force to perform a forced shutdown.
.NOTES 
    File Name  : Stop-PsftDomain.ps1 
    Author     : Scott Kearney - scott@kearney.tk 
    Requires   : PowerShell V3 
.EXAMPLE 
    Stop-PsftDomain -PS_HOME C:\psoft\PS_HOME -PS_CFG_HOME C:\psoft\PS_CFG_HOME -ServerType AppServer -Domain DOMAIN1
    Stops the domain named DOMAIN1.
.EXAMPLE 
    Start-PsftDomain C:\psoft\PS_HOME C:\psoft\PS_CFG_HOME DOMAIN1 -Force
    Stops the domain named DOMAIN1 forcibly.
.PARAMETER PS_HOME
    The full path to the PS_HOME directory for this domain.
.PARAMETER PS_CFG_HOME
    The full path to the PS_CFG_HOME directory for this domain.
.PARAMETER ServerType
    The type of server on which to perform the action.
.PARAMETER Domain
    The name of the domain on which to perform the action.
.PARAMETER Force
    If specified, will force the shutdown of this domain.
#> 
function Stop-PsftDomain
{
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='High')]
    [OutputType([int])]
    Param
    (
        # The full path to the PS_HOME directory for this domain.
        # See http://docs.oracle.com/cd/E41633_01/pt853pbh1/eng/pt/tsvt/concept_UnderstandingPS_HOMEandPS_CFG_HOME-eb7ece.html
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The full path to the PS_HOME directory for this domain.",
                   Position=0)]
        [ValidateScript({Validate_PS_HOME $_})]
        [String]
        $PS_HOME,

        # The full path to the PS_CFG_HOME directory for this domain.
        # See http://docs.oracle.com/cd/E41633_01/pt853pbh1/eng/pt/tsvt/concept_UnderstandingPS_HOMEandPS_CFG_HOME-eb7ece.html
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The full path to the PS_CFG_HOME directory for this domain.",
                   Position=1)]
        [ValidateScript({Validate_PS_CFG_HOME $_})]
        [String]
        $PS_CFG_HOME,

        # The type of server on which to perform the action.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The type of server on which to perform the action.",
                   Position=2)]
        [ValidateSet("AppServer","PrcsScheduler","SearchServer","WebServer")]
        $ServerType,

        # The name of the domain on which to perform the action.
        # Should be a directory under the PS_CFG_HOME
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "The name of the domain on which to perform the action.",
                   Position=3)]
        [ValidateScript({Validate_Domain $PS_CFG_HOME $ServerType $_})]
        [String]
        $Domain,

        # If specified, will force the shutdown of this domain.
        [Parameter(Mandatory=$false,
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage = "If specified, will force the shutdown of this domain.",
                   Position=4)]
        [Switch]
        $Force
    )

    Begin
    {
    }
    Process
    {
        # Set up variables
		$return = @()
        $PSAdmin = @{Result=@();Error="";}
        $completedServers = 0
        $totalServers = 0
		
        # Decide whether to do a normal shutdown or a forced shutdown
        if($Force){
            switch ($ServerType)
            {
                'AppServer'     {$Command = "shutdown!"}
                'PrcsScheduler' {$Command = "kill"}
                'SearchServer'  {$Command = "shutdown!"}
                'WebServer'     {$Command = "shutdown!"}
            }
            
        } else {
            switch ($ServerType)
            {
                'AppServer'     {$Command = "shutdown"}
                'PrcsScheduler' {$Command = "stop"}
                'SearchServer'  {$Command = "shutdown"}
                'WebServer'     {$Command = "shutdown"}
            }
        }

        if($PSCmdlet.ShouldProcess($Domain, "Stop-PsftDomain"))
        {
            # Retrieve the number of servers which will be stopped (used for progress bar)
           
            $totalServers = @(Get-PsftStatus -PS_HOME $PS_HOME -PS_CFG_HOME $PS_CFG_HOME -ServerType $ServerType -Domain $Domain -Target Server).Count

            # Invoke PSAdmin to stop the domain
            $PSAdminJob = Invoke-PSAdmin -PS_HOME $PS_HOME -PS_CFG_HOME $PS_CFG_HOME -ServerType $ServerType -Domain $Domain -Command $Command -AsJob

            # While data is being returned, parse it for the progress bar
            while($PSAdminJob | Select -exp HasMoreData){
                $ProgName = ""

                $MoreData = ($PSAdminJob | Receive-Job) 

                $thisErrors = (($MoreData | Where {$_.GetType() -notlike "String"}) -join "")
                $thisResults = $MoreData | Where {$_.GetType() -like "String"}
                $PSAdmin.Error += $thisErrors
                $PSAdmin.Result += $thisResults

                $thisErrors -split "`n" | Select-String "^[\s]*Server Id" | %{
                    $ProgName = "$(([String]$_ -replace ".*Group Id = ([\w]*).*","`$1")), $(([String]$_ -replace ".*Server Id = ([\w]*).*","`$1"))"
                    Write-Progress -Activity "Stopping PeopleSoft $ServerType" -Status "$Domain" -CurrentOperation $ProgName -PercentComplete ((($completedServers++)/$totalServers)*100)
                }
            }

            # After the data is done processing, remove the progress bar
            Write-Progress -Activity "Starting PeopleSoft $ServerType" -Status "$Domain" -PercentComplete 100 -Completed

            # Now that we have all of the data, split it up into separate lines
            $PSAdmin.Error = $PSAdmin.Error -split "`n"

            # Write the information out, if verbose
            Write-Verbose "*** Errors ***"
            $PSAdmin.Error | %{ Write-Verbose $_ }
        
            Write-Verbose "*** Results ***"
            $PSAdmin.Result | %{ Write-Verbose $_ }

            # Catch any errors that came up during shutdown.
		    switch($PSAdmin.Error){
                {$_ -match "CMDTUX_CAT:764"} { Write-Error "Can't attach to the Bulletin Board." -CategoryTargetName "CMDTUX" -CategoryTargetType 764 -ErrorId 764 -RecommendedAction "Check the userlog for additional diagnostic messages. Normally this error implies that the TUXCONFIG environment variable is not set correctly, or that the application is not booted."; break;}
			    {$_ -match "error"} { Write-Error "There was an error stopping the domain $Domain`: $_" }
		    }
        
            # The $PSAdmin.Error portion has the information that we need to process
            $result = $PSAdmin.Error
		
            $return = @()

            # Parse out the resulting information and create an object with the relevant information.
            $result | Where {$_ -match "^[\s]*Server Id"} | %{
                $return += New-Object Object |
                    Add-Member NoteProperty ServerId       (([String]$_ -replace ".*Server Id = ([\w]*).*","`$1")) -PassThru | 
                    Add-Member NoteProperty GroupId        (([String]$_ -replace ".*Group Id = ([\w]*).*","`$1")) -PassThru |
                    Add-Member NoteProperty Machine        (([String]$_ -replace ".*Machine = ([\w]*).*","`$1")) -PassThru | 
                    Add-Member NoteProperty Status         (([String]$_ -replace ".*:[\s]*([^:]+)$","`$1").Trim(" ")) -PassThru
            }
        }

		return $return
    }
    End
    {
    }
}